﻿

namespace System.Extensions.Web.UI.WebControls
{
  using System;
  using System.Collections.Generic;
  using System.ComponentModel;
  using System.Web;
  using System.Web.UI;
  using System.Web.UI.WebControls;
  using System.Extensions.Internal;
  using System.Security.Permissions;

  /// <summary>
  /// Evaluates the value of a <see cref="CheckBox"/> to ensure the user selects the appropriate value.
  /// </summary>
  [ToolboxData("<{0}:CheckBoxRequiredFieldValidator runat=\"server\" ErrorMessage=\"CheckBoxRequiredFieldValidator\"></{0}:CheckBoxRequiredFieldValidator>")]
  public class CheckBoxRequiredFieldValidator : BaseValidator, IScriptControl
  {
    private ScriptManager scriptManager;
    private bool requiredValue = true;

    /// <summary>
    /// Gets or sets a value indicating whether <b>true</b> is considered valid or <b>false</b>.
    /// </summary>
    [SRCategory("Category_Behavior")]
    [DefaultValue(true)]
    [Description("The value that is considered required.")]
    public bool RequiredValue
    {
      get { return this.requiredValue; }
      set { this.requiredValue = value; }
    }

    /// <summary>
    /// Gets or sets the input control to validate.
    /// </summary>
    [Description("The CheckBox to validate.")]
    [TypeConverter(typeof(Design.CheckBoxConverter))]
    public new string ControlToValidate
    {
      get { return base.ControlToValidate; }
      set { base.ControlToValidate = value; }
    }

    IEnumerable<ScriptDescriptor> IScriptControl.GetScriptDescriptors()
    {
      ScriptControlDescriptor descriptor = new ScriptControlDescriptor("DotNetLib.CheckBoxRequiredFieldValidator", ClientID);

      descriptor.AddProperty("RequiredValue", this.RequiredValue);

      yield return descriptor;
    }

    IEnumerable<ScriptReference> IScriptControl.GetScriptReferences()
    {
      ScriptReference reference = new ScriptReference();

      reference.Assembly = "DotNetLib";
      reference.Name = "DotNetLib.Web.UI.WebControls.Validators.js";

      yield return reference;
    }

    /// <summary>
    /// This is a check of properties to determine any errors made by the developer.
    /// </summary>
    /// <returns><b>True</b> if the control properties are valid; otherwise, <b>false</b>.</returns>
    protected override bool ControlPropertiesValid()
    {
      if (string.IsNullOrEmpty(this.ControlToValidate))
      {
        throw new HttpException("ControlToValidate is blank");
      }

      CheckBox list = NamingContainer.FindControl(this.ControlToValidate) as CheckBox;
      if (list == null)
      {
        throw new NotSupportedException("ControlToValidate is not a CheckBox");
      }

      return true;
    }

    /// <summary>
    /// Determines whether the content in the input control is valid.
    /// </summary>
    /// <returns><b>True</b> if the control is valid; otherwise, <b>false</b>.</returns>
    protected override bool EvaluateIsValid()
    {
      CheckBox box = NamingContainer.FindControl(this.ControlToValidate) as CheckBox;
      return box.Checked == this.requiredValue;
    }

    /// <summary>
    /// Raises the <see cref="Control.PreRender"/> event.
    /// </summary>
    /// <param name="e">An <see cref="EventArgs"/> that contains the event data.</param>
    protected override void OnPreRender(EventArgs e)
    {
      if (!DesignMode && DetermineRenderUplevel())
      {
        this.scriptManager = ScriptManager.GetCurrent(Page);
        if (this.scriptManager == null)
        {
          throw new HttpException("A ScriptManager control must exist on the current page.");
        }

        this.scriptManager.RegisterScriptControl(this);
      }

      base.OnPreRender(e);
    }

    /// <summary>
    /// Displays the control on the client.
    /// </summary>
    /// <param name="writer">An <see cref="HtmlTextWriter"/> that contains the output stream for rendering on the client.</param>
    protected override void Render(HtmlTextWriter writer)
    {
      if (!DesignMode && DetermineRenderUplevel())
      {
        this.scriptManager.RegisterScriptDescriptors(this);
      }

      base.Render(writer);
    }
  }
}
